package com.zyc.app.woa;

import android.text.TextUtils;
import com.zyc.app.woa.data.AccountInfo;
import com.zyc.app.woa.data.ArticleItem;
import com.zyc.app.woa.data.CachedArticle;
import com.zyc.app.woa.data.Gzhcb;
import com.zyc.app.woa.db.DBManager;
import com.zyc.app.woa.utils.StorageUtils;
import com.zyc.app.woa.utils.Trace;
import org.apache.commons.io.IOUtils;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.*;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Author: yingchang.zhang
 * Date  : 2014/11/28
 */
public class ArticlesDownloadManager {
    public static final int ID_TRIM_LENGTH = 6;
    public static final Pattern SN_PATTERN = Pattern.compile("sn=(\\w+)");
    public static final String ACCOUNT_ARTICLES_URL = "http://weixin.sogou.com/gzhjs?cb=sogou.weixin.gzhcb&openid=%s&page=%s&t=%s";
    private AccountInfo mAccountInfo;


    public void startDownload(AccountInfo accountInfo) {
        mAccountInfo = accountInfo;
        Trace.log("start download AccountInfo: " + mAccountInfo.toString());
        Gzhcb gzhcb = downloadAccountArticlesList();
        Trace.log("download: " + mAccountInfo.name + " info: " + gzhcb);
        if (null != gzhcb) {
            downloadArticleList(gzhcb);
        }
    }

    private Gzhcb downloadAccountArticlesList() {
        int currPage = 1;
        String body;
        Gzhcb gzhcb = null;
        Gzhcb accountArticles = null;
        int totalArticles = mAccountInfo.getSubscribeArticlesNum();
        int size = 0;
        try {
            do {
                body = reguestText(mAccountInfo.getOpenId(), currPage);
                gzhcb = Gzhcb.build(body);
                if (null == accountArticles) {
                    if (null != gzhcb) {
                        totalArticles = totalArticles > gzhcb.totalItems ? gzhcb.totalItems : totalArticles;
                        accountArticles = gzhcb;
                    } else {
                        break;
                    }
                } else {
                    accountArticles.addArticles(gzhcb.articles);
                    size = accountArticles.getArticleCount();
                }
                currPage++;
                Trace.log("downloading page: " + currPage + " size: " + size);
            } while (size < totalArticles);

            if (null != accountArticles) {
                Trace.log(accountArticles.toString());
            }

//            Utils.log("content: " + response.body());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return accountArticles;
    }

    private void downloadArticleList(Gzhcb gzhcb) {
        String path = StorageUtils.getAccountArticlesCachePath(mAccountInfo.wxId);
        StorageUtils.createPathIfNotExist(path);
        if (null != gzhcb && null != gzhcb.articles) {
            Trace.log("download articles : " + gzhcb.articles.toString());
            String articlePath;
            for (ArticleItem articleItem : gzhcb.articles) {
                if (!TextUtils.isEmpty(articleItem.url)) {
                    articlePath = StorageUtils.getAccountArticlePath(path, parseMsgId(articleItem.url));
                    if (!isArticleExist(articlePath)) {
                        downloadArticle(articleItem, articlePath);
                    }
                }
            }
        }
    }

    private boolean isArticleExist(String articlePath) {
        return new File(articlePath).exists();
    }

    private void downloadArticle(ArticleItem articleItem, String articlePath) {
        StorageUtils.createPathIfNotExist(articlePath);
        try {
            Document document = Jsoup.connect(articleItem.url).get();
            removeNodes(document, "#js_pc_qr_code");
            removeNodes(document, "div.rich_media_tool#js_toobar");
            removeNodes(document, "div#js_bottom_ad_area");
            removeNodes(document, "script");
            addImgCover(document, articleItem.imgLink);
            replaceRemoteResToLocal(document, articlePath);
            String htmlPath = articlePath + File.separator + StorageUtils.ARTICLE_HTML_FILE;
            storeHtml(document.toString(), htmlPath);
            CachedArticle cachedArticle = new CachedArticle(articleItem);
            cachedArticle.cachedTime = System.currentTimeMillis();
            cachedArticle.wxId = mAccountInfo.wxId;
            cachedArticle.cacheFile = htmlPath;
            StorageUtils.cachePic(cachedArticle.imgLink);
            DBManager.insertArticle(cachedArticle);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void modifyElementsResAttr(Elements links, final String attrName, String articleCachePath) {
        if (null != links && !links.isEmpty()) {
            String href;
            String absPath;
            String relativePath;
            for (Element link : links) {
                href = link.attr(attrName);
                absPath = getUniquePath(articleCachePath + File.separator + StorageUtils.RES_FOLDER + File.separator + StorageUtils.getFileName(href));
                relativePath = "." + File.separator + StorageUtils.RES_FOLDER + File.separator + StorageUtils.getFileName(absPath);
                downloadResToPath(href, absPath);
                link.attr(attrName, relativePath);
                if ("img".equals(link.tagName())) {
                    link.attr("src", relativePath);
                }
            }
        }
    }

    private static void downloadResToPath(String url, String savePath) {
        BufferedInputStream bis = null;
        FileOutputStream fos = null;

        try {
            URL picUrl = new URL(url);
            File file = StorageUtils.createFileIfNotExist(savePath);
            bis = new BufferedInputStream(picUrl.openStream());
            fos = new FileOutputStream(file);

            byte[] buffer = new byte[1024];
            int read;
            while ((read = bis.read(buffer, 0, 1024)) != -1) {
                fos.write(buffer, 0, read);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(fos);
            IOUtils.closeQuietly(bis);
        }
    }

    private static void storeHtml(String html, String path) {
//        Trace.log("replace text: " + html);
        File file = new File(path);
        FileWriter writer = null;
        try {
            writer = new FileWriter(file);
            writer.write(html);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();

            try {
                if (null != writer) {
                    writer.close();
                }
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

    private static String getUniquePath(String absPath) {
        int index = 0;
        File file;
        do {
            file = new File(absPath);
            if (!file.exists()) {
                break;
            }
            index++;
            absPath += index;
        } while (true);

        return absPath;
    }

    private static void replaceRemoteResToLocal(Document document, String articleCachePath) {
        modifyElementsResAttr(document.select("[src^=http://]"), "src", articleCachePath);
        modifyElementsResAttr(document.select("[data-src^=http://]"), "data-src", articleCachePath);
        modifyElementsResAttr(document.select("[href^=http://]"), "href", articleCachePath);
    }

    private static void removeNodes(Document document, String tag) {
        Elements elements = document.select(tag);
        if (null != elements && !elements.isEmpty()) {
            for (Element element : elements) {
                if (null != element) {
                    element.remove();
                }
            }
        }
    }

    private static void addImgCover(Document document, String picUrl) {
        Elements container = document.select("div.rich_media_thumb#media");
        if (null != container && !container.isEmpty()) {
            Element imgElement = container.first().appendElement("img");
            imgElement.attr("id", "js_cover");
            imgElement.attr("onerror", "this.parentNode.removeChild(this)");
            imgElement.attr("src", picUrl);
        }
    }

    private String parseMsgId(String msgUrl) {
        String id = WxConfig.DEFAULT_ID;
        Matcher matcher = SN_PATTERN.matcher(msgUrl);
        if (matcher.find()) {
            id = matcher.group(1);
            if (!TextUtils.isEmpty(id) && id.length() > ID_TRIM_LENGTH) {
                return id.substring(0, ID_TRIM_LENGTH);
            }
        }
        Trace.log("parse msg id: " + id);
        return id;
    }

    public static String reguestText(String openId, int page) throws IOException {
        String requestUrl = buildAccountArticlesUrl(openId, page);
        Trace.log("requestUrl: " + requestUrl);
//        Document document = getDocument(requestUrl, null);
//        String body = document.toString();
        Connection.Response response =  Jsoup.connect(requestUrl)
                .ignoreContentType(true)
                .followRedirects(true)
                .timeout(5000)
                .data("Accept-Encoding", "gzip")
                .data("Content-Type", "application/x-javascript; charset=utf-8")
                .data("P3P", "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"")
                .userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36").execute();
        String body = response.body();
//        if (!hasBody(document)) {
//            Trace.log("=================no body, document content:  " + body);
//            String cookie = readLine(body, "document.cookie");
//            Date date = new Date();
//            date.setTime(date.getTime() + 5 * 24 * 3600 * 1000);
//            cookie += date.toGMTString();
//            String href = readLine(body, "document.location.href");
//            href = "http://weixin.sogou.com" + href;
//
//            document = getDocument(href, buildCookies(cookie));
//            body = document.toString();
//            Trace.log("cookie:" + cookie);
//            Trace.log("href:" + href);
//        }

        Trace.log("========response:" + body);
        int start = body.indexOf("({");
        int end = body.indexOf("})");
        if (start >= 0 && end >= 0 && end > start) {
            body = body.substring(start + 1, end + 1);
        }
        return body;
    }

    private static Document getDocument(String requestUrl, HashMap<String, String> cookies) throws IOException {
        if (null != cookies) {
            return Jsoup.connect(requestUrl)
                    .ignoreContentType(true)
                    .followRedirects(true)
                    .timeout(5000)
                    .cookies(cookies)
                    .userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36").get();
        } else {
            return Jsoup.connect(requestUrl)
                    .ignoreContentType(true)
                    .followRedirects(true)
                    .timeout(5000)
                    .userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36").get();
        }
    }

    private static boolean hasBody(Document document) {
        Element body = document.body();
        if (null != body) {
            Elements elements = body.getAllElements();
            return null != elements && elements.size() > 1;
        }
        return false;
    }

    private static HashMap<String, String> buildCookies(String cookieText) {
        String[] cookies = cookieText.split(";");
        String[] values;

        HashMap<String, String> map = new HashMap<String, String>();
        for (String text : cookies) {
            values = text.split("=");
            if (values.length > 1) {
                map.put(values[0], values[1]);
            }
        }
        return map;
    }

    private static String readLine(String content, String lineTag) {
        int index = content.lastIndexOf(lineTag);
        if (index > 0) {
            String destText = content.substring(index);
            String[] texts = destText.split("\"");
            return texts[1];
        }

        return null;
    }

    public static String buildAccountArticlesUrl(String openId, int page) {
        long time = System.currentTimeMillis();
        return String.format(ACCOUNT_ARTICLES_URL, openId, page + "", time);
    }
}
